package com.gel.codegeneration.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.gel.codegeneration.ai.model.enums.CodeGenTypeEnum;
import com.gel.codegeneration.common.Annotation.AuthCheck;
import com.gel.codegeneration.common.constant.AppConstant;
import com.gel.codegeneration.common.constant.UserConstant;
import com.gel.codegeneration.common.enums.ErrorCode;
import com.gel.codegeneration.convention.exception.BusinessException;
import com.gel.codegeneration.convention.result.BaseResponse;
import com.gel.codegeneration.convention.result.ResultUtils;
import com.gel.codegeneration.model.dto.req.app.*;
import com.gel.codegeneration.model.dto.req.user.DeleteRequest;
import com.gel.codegeneration.model.dto.resp.app.AppVO;
import com.gel.codegeneration.model.entity.User;
import com.gel.codegeneration.service.ProjectDownloadService;
import com.gel.codegeneration.service.UserService;
import com.gel.codegeneration.utils.ThrowUtils;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import com.gel.codegeneration.model.entity.App;
import com.gel.codegeneration.service.AppService;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.publisher.MonoSink;

import java.io.File;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * 应用控制层。
 *
 * @author <a>gel</a>
 */
@RestController
@RequestMapping("/app")
public class AppController {

    @Resource
    private AppService appService;
    @Resource
    private UserService userService;
    @Resource
    private ProjectDownloadService projectDownloadService;
    private static final String PREVIEW_ROOT_DIR = AppConstant.CODE_OUTPUT_ROOT_DIR;
    /**
     * @description: 部署应用
     * @author: gel
     * @param: [appDeployRequest, request]
     * @return: com.gel.codegeneration.convention.result.BaseResponse<java.lang.String>
     **/
    @PostMapping("/deploy")
    public BaseResponse<String> deployApp(@RequestBody AppDeployRequest appDeployRequest, HttpServletRequest  request) {
        ThrowUtils.throwIf(appDeployRequest == null, ErrorCode.PARAMS_ERROR);
        Long appId = appDeployRequest.getAppId();
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR);
        User loginUser = userService.getLoginUser(request);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);
        String deployUrl = appService.deploy(appId, loginUser);
        return ResultUtils.success(deployUrl);
    }

        /**
         * @description: 跳转ai界面
         * @author: gel
         * @param: [appId, userMessage, request]
         * @return: reactor.core.publisher.Flux<org.springframework.http.codec.ServerSentEvent<java.lang.String>>
         **/

    @GetMapping(value = "/chat/gen/code",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>> chatToGenCode(@RequestParam Long appId, @RequestParam String message, HttpServletRequest request) {
        //参数校验
        ThrowUtils.throwIf(appId == null||appId<=0,ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(StrUtil.isBlank(message),ErrorCode.PARAMS_ERROR,"用户消息不能为空");
        //获取登录用户
        User loginUser = userService.getLoginUser(request);
        Flux<String> genCode = appService.chatToGenCode(appId, message, loginUser);
        //转换为服务器推送事件（ServerSentEvent格式）
        return  genCode.map(chunk->{
            Map<String,String> chunkMap = Map.of("d", chunk);
            String jsonStr = JSONUtil.toJsonStr(chunkMap);
            return ServerSentEvent.<String>builder()
                    .data(jsonStr)
                    .build();
        }).concatWith(Mono.just(
                //发送结束事件
                ServerSentEvent.<String>builder()
                        .event("done")
                        .data("")
                        .build()
                )
        );


    }

    /**
     * @description: 创建应用
     * @author: gel
     * @param: [appAddRequest, request]
     * @return: com.gel.codegeneration.convention.result.BaseResponse<java.lang.Long>
     **/
    @PostMapping("/add")
    public BaseResponse<Long> addapp(@RequestBody AppAddRequest appAddRequest, HttpServletRequest  request) {
        //参数校验
        ThrowUtils.throwIf(appAddRequest == null, ErrorCode.PARAMS_ERROR);
        //获取登录用户
        User loginUser = userService.getLoginUser(request);
        Long appId = appService.createApp(appAddRequest, loginUser);
        return ResultUtils.success(appId);



    }

    /**
     * @description: 更新应用
     * @author: gel
     * @param: [appUpdateRequest, request]
     * @return: com.gel.codegeneration.convention.result.BaseResponse<java.lang.Boolean>
     **/
    @PostMapping("/update")
    public BaseResponse<Boolean> update(@RequestBody AppUpdateRequest appUpdateRequest,HttpServletRequest  request) {
        //参数校验
        if(appUpdateRequest == null||appUpdateRequest.getId() == null){
            throw  new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //查询用户是否存在
        App app = appService.getById(appUpdateRequest.getId());
        ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR);
        Long appId = appUpdateRequest.getId();
        //判断用户是否有权限（用户只能更新自己的应用）
        User loginUser = userService.getLoginUser(request);
        Long loginUserId = loginUser.getId();
        if(!app.getUserId().equals(loginUserId)){
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        //更新操作
        App newApp=App.builder()
                .id(appId)
                .appName(appUpdateRequest.getAppName())
                .editTime(LocalDateTime.now())
                .build();
        boolean result = appService.updateById(newApp);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(result);


    }

    /**
     * @description: 删除应用
     * @author: gel
     * @param: [deleteRequest, request]
     * @return: com.gel.codegeneration.convention.result.BaseResponse<java.lang.Boolean>
     **/

    @PostMapping("/delete")
    public BaseResponse<Boolean> remove(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        if(deleteRequest == null||deleteRequest.getId() <=0){
            throw  new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //获取登录用户
        User loginUser = userService.getLoginUser(request);
        //判断是否存在
        Long appId = deleteRequest.getId();
        App app = appService.getById(appId);
        ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR);
        //进管理员与用户可删除
        if(!app.getUserId().equals(loginUser.getId()) && !loginUser.getUserRole().equals(UserConstant.ADMIN_ROLE)){
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        boolean result = appService.removeById(appId);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return  ResultUtils.success(result);

    }

    @GetMapping("/get/vo")
    public BaseResponse<AppVO> getAppVOById(long id) {
        ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR);
        App app = appService.getById(id);
       ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR);
        AppVO appVO = appService.getAppVO(app);
        return ResultUtils.success(appVO);
    }

    /**
     * @description: 用户分页查询应用
     * @author: gel
     * @param: [appQueryRequest, request]
     * @return: com.gel.codegeneration.convention.result.BaseResponse<com.mybatisflex.core.paginate.Page<com.gel.codegeneration.model.dto.resp.app.AppVO>>
     **/
    @PostMapping("/my/list/page/vo")
    public BaseResponse<Page<AppVO>> listMyAppVOByPage(@RequestBody AppQueryRequest appQueryRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(appQueryRequest == null, ErrorCode.PARAMS_ERROR);
        //限制每页查询数量
        long pageSize = appQueryRequest.getPageSize();
        ThrowUtils.throwIf(pageSize > 20, ErrorCode.PARAMS_ERROR,"每页最多查询20个应用");
        //只能查询当前用户的应用
        appQueryRequest.setUserId(userService.getLoginUser(request).getId());
        QueryWrapper queryWrapper = appService.getQueryWrapper(appQueryRequest);
        Page<App> page = appService.page(new Page<>(appQueryRequest.getPageNum(), appQueryRequest.getPageSize()), queryWrapper);
        List<AppVO> appVOList = appService.getListAppVO(page.getRecords());
        Page<AppVO> appVOPage = new Page<>(appQueryRequest.getPageNum(), appQueryRequest.getPageSize(), page.getTotalRow());
        appVOPage.setRecords(appVOList);
        return ResultUtils.success(appVOPage);
    }
    //用户分页查询精选应用
    /**
     * 分页获取精选应用列表
     *
     * @param appQueryRequest 查询请求
     * @return 精选应用列表
     */
    @PostMapping("/good/list/page/vo")
    public BaseResponse<Page<AppVO>> listGoodAppVOByPage(@RequestBody AppQueryRequest appQueryRequest) {
        ThrowUtils.throwIf(appQueryRequest == null, ErrorCode.PARAMS_ERROR);
        // 限制每页最多 20 个
        long pageSize = appQueryRequest.getPageSize();
        ThrowUtils.throwIf(pageSize > 20, ErrorCode.PARAMS_ERROR, "每页最多查询20个应用");
        long pageNum = appQueryRequest.getPageNum();
        // 只查询精选的应用
        appQueryRequest.setPriority(AppConstant.GOOD_APP_PRIORITY);
        QueryWrapper queryWrapper = appService.getQueryWrapper(appQueryRequest);
        // 分页查询
        Page<App> appPage = appService.page(Page.of(pageNum, pageSize), queryWrapper);
        // 数据封装
        Page<AppVO> appVOPage = new Page<>(pageNum, pageSize, appPage.getTotalRow());
        List<AppVO> appVOList = appService.getListAppVO(appPage.getRecords());
        appVOPage.setRecords(appVOList);
        return ResultUtils.success(appVOPage);
    }

    //管理员删除应用
    /**
     * 管理员删除应用
     *
     * @param deleteRequest 删除请求
     * @return 删除结果
     */
    @PostMapping("/admin/delete")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> deleteAppByAdmin(@RequestBody DeleteRequest deleteRequest) {
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        long id = deleteRequest.getId();
        // 判断是否存在
        App oldApp = appService.getById(id);
        ThrowUtils.throwIf(oldApp == null, ErrorCode.NOT_FOUND_ERROR);
        boolean result = appService.removeById(id);
        return ResultUtils.success(result);
    }

    //管理员更新应用
    @PostMapping("/admin/update")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> updateAppByAdmin(@RequestBody AppAdminUpdateRequest appAdminUpdateRequest) {
        if (appAdminUpdateRequest == null||appAdminUpdateRequest.getId() == null ) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Long id = appAdminUpdateRequest.getId();
        App app = appService.getById(id);
        ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR);
        App newApp = BeanUtil.toBean(appAdminUpdateRequest, App.class);
        newApp.setEditTime(LocalDateTime.now());
        boolean result = appService.updateById(newApp);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(result);

    }
    //管理员分页查询应用
    @PostMapping("/admin/list/page/vo")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Page<AppVO>> listAppVOByPage(@RequestBody AppQueryRequest appQueryRequest) {
       ThrowUtils.throwIf(appQueryRequest == null, ErrorCode.PARAMS_ERROR);
        QueryWrapper queryWrapper = appService.getQueryWrapper(appQueryRequest);
        Page<App> page = appService.page(new Page<>(appQueryRequest.getPageNum(), appQueryRequest.getPageSize()), queryWrapper);
        Page<AppVO> result = new Page<>(page.getPageNumber(), page.getPageSize(), page.getTotalRow());
        List<AppVO> appVOList = appService.getListAppVO(page.getRecords());
        result.setRecords(appVOList);
        return ResultUtils.success(result);
    }
    //管理员获取应用详情
    @GetMapping("admin/get/vo")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<AppVO> getAppVOByIdByAdmin(Long id) {
        ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR);
        App app = appService.getById(id);
        ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR);
        AppVO appVO = appService.getAppVO(app);
        return ResultUtils.success(appVO);
    }



    /**
     * 下载应用代码
     *
     * @param appId    应用ID
     * @param request  请求
     * @param response 响应
     */
    @GetMapping("/download/{appId}")
    public void downloadAppCode(@PathVariable Long appId,
                                HttpServletRequest request,
                                HttpServletResponse response) {
        // 1. 基础校验
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用ID无效");
        // 2. 查询应用信息
        App app = appService.getById(appId);
        ThrowUtils.throwIf(app == null, ErrorCode.NOT_FOUND_ERROR, "应用不存在");
        // 3. 权限校验：只有应用创建者可以下载代码
        User loginUser = userService.getLoginUser(request);
        if (!app.getUserId().equals(loginUser.getId())) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "无权限下载该应用代码");
        }
        // 4. 构建应用代码目录路径（生成目录，非部署目录）
        String codeGenType = app.getCodeGenType();
        String sourceDirName = codeGenType + "_" + appId;
        String sourceDirPath = AppConstant.CODE_OUTPUT_ROOT_DIR + File.separator + sourceDirName;
        // 5. 检查代码目录是否存在
        File sourceDir = new File(sourceDirPath);
        ThrowUtils.throwIf(!sourceDir.exists() || !sourceDir.isDirectory(),
                ErrorCode.NOT_FOUND_ERROR, "应用代码不存在，请先生成代码");
        // 6. 生成下载文件名（不建议添加中文内容）
        String downloadFileName = String.valueOf(appId);
        // 7. 调用通用下载服务
        projectDownloadService.downloadProjectAsZip(sourceDirPath, downloadFileName, response);
    }






}
